package org.test.java;

import static org.test.java.ShuaTa.print;
import static org.test.java.ShuaTa.judgeChips;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.GZIPInputStream;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;

import com.google.gson.Gson;

/**
 * Hello world!
 * 
 */
public class App {

	static String _sid = "0123456789";
	static String logFile = "compete.log";
	final static String SID_KEY = "sid";
	final static String LOG_FILE_KEY = "log_file";
	
	static boolean test = false;

	private static int competeRank = 10000;
	private static int winRate = 30;
	static int energyControl = 10;
	
	@SuppressWarnings("rawtypes")
	public static void main(String[] args) throws IOException {
		Properties props = new Properties();
		InputStream is = App.class.getClassLoader().getResourceAsStream(
				"app.properties");
		try {
			if (is != null)
				props.load(is);
			if (props.containsKey(SID_KEY))
				_sid = props.getProperty(SID_KEY);
			if (props.containsKey(LOG_FILE_KEY))
				logFile = props.getProperty(LOG_FILE_KEY);
			if(props.containsKey("competeRank"))
				competeRank = Integer.parseInt(props.getProperty("competeRank"));
			if(props.containsKey("winRate"))
				winRate = Integer.parseInt(props.getProperty("winRate"));
			if(props.containsKey("energyControl"))
				energyControl = Integer.parseInt(props.getProperty("energyControl"));
		} finally {
			is.close();
		}
		log("SID=" + _sid);
		log("LOG_FILE=" + logFile);
		log("args:" + Arrays.asList(args));
		if (args.length == 2 && "-b".equals(args[0])) {
			new Shop(_sid, props).buyCard(Integer.parseInt(args[1]));
			return;
		}
		if(args.length==3 && "-S".equals(args[0])){
			System.out.println(" -S {level} {cardId}");
			int level = Integer.parseInt(args[1]);
			long cardId = Long.parseLong(args[2]);
			new Strength(_sid, props).strength(level, cardId);
			return;
		}
		if(args.length == 2 && "-m".equals(args[0])){
			new Meditation(_sid, props).meditation(Integer.parseInt(args[1]));
			return;
		}
		if (test)
			return;
		new Thread(new RankCompete(_sid, props)).start();
		new Thread(new EditMapStage(_sid, props)).start();
		new Thread(new Thiefe(_sid, props)).start();
		new Thread(new Boss(_sid, props)).start();
		new Thread(new TanSuo(_sid, props)).start();
		new Thread(new ShuaTa(_sid, props)).start();
		while (true) {
			try {
				// 等待竞技时间
				int time = 600;
				Map map = new HashMap();
				while (time > 0) {
					String listResult = list();
					Gson gson = new Gson();
					map = (Map) gson.fromJson(listResult, Map.class);
					time = sleeptimeForCompetitor(map);
					if (time > 0) {
						log("等待自由竞技休息时间..." + time);
						try {
							Thread.sleep(time * 1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				// 匹配合适的竞技者
				String id = getSuitableCompetitor(map);
				if (id == null){
					continue;
				}
				// 开始竞技
				compete(id);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
	}

	@SuppressWarnings("rawtypes")
	public static void compete(String competitor) throws IOException {
		HttpClient client = new HttpClient();
		PostMethod post = new PostMethod(
				"http://s7.mysticalcard.com/arena.php?do=FreeFight&v=856&phpp=ANDROID&phpl=ZH_CN&pvc=1.3.0&pvb=2013-06-19%2016%3A27%3A25");
		try {
			post.setRequestHeader("Cookie", "_sid=" + _sid);
			RequestEntity entity = new StringRequestEntity(
					"isManual=0&Competitor=" + competitor,
					"application/x-www-form-urlencoded", "UTF8");
			post.setRequestEntity(entity);
			int status = client.executeMethod(post);
			if (status != 200)
				throw new HttpException("status = " + status);
			String result = readGzip(post);
			Gson gson = new Gson();
			Map map = (Map) gson.fromJson(result, Map.class);
			if (Double.valueOf(map.get("status").toString()).intValue() == 0) {
				log(result);
				return;
			}
			Map data = (Map) map.get("data");
			logForCompete(result);
			int win =  (Double.valueOf(data.get("Win").toString())).intValue();
			String attack = (String) ((Map) data.get("AttackPlayer"))
					.get("NickName");
			String defend = (String) ((Map) data.get("DefendPlayer"))
					.get("NickName");
			log(attack + "<--------->" + defend);
			if (win == 1) {
				log("Wined.");
				Object extDataObj = data.get("ExtData");
				if (!(extDataObj instanceof Map))
					return;
				Map extData = (Map) extDataObj;
				if (!extData.containsKey("Award"))
					return;
				Map award = (Map) extData.get("Award");
				if (!award.containsKey("Chip"))
					return;
				Object chip = award.get("Chip");
				log("Get chip " + chip);
			}
		} finally {
			post.releaseConnection();
		}
	}

	public static void logForCompete(String result) throws IOException {
		FileOutputStream fos = new FileOutputStream(logFile, true);
		try {
			fos.write(result.getBytes());
		} finally {
			fos.close();
		}
	}

	public static String list() throws HttpException, IOException {
		HttpClient client = new HttpClient();
		PostMethod post = new PostMethod(
				"http://s7.mysticalcard.com/arena.php?do=GetCompetitors&v=9383&phpp=ANDROID&phpl=ZH_CN&pvc=1.1.0&pvb=2013-01-25%2016%3A28%3A32");
		try {
			post.setRequestHeader("Cookie", "_sid=" + _sid);
			int status = client.executeMethod(post);
			if (status != 200)
				throw new HttpException("status = " + status);
			return readGzip(post);
		} finally {
			post.releaseConnection();
		}
	}

	@SuppressWarnings("rawtypes")
	public static int sleeptimeForCompetitor(Map listResult) {
		Map data = (Map) listResult.get("data");
		Double countDown = Double.valueOf(data.get("Countdown").toString());
		if (countDown == null) {
			countDown = Double.valueOf(600);
		}
		return countDown.intValue();
	}

	static int noChipCount = 0;

	@SuppressWarnings("rawtypes")
	public static String getSuitableCompetitor(Map listResult)
			throws InterruptedException, IOException {
		Map data = (Map) listResult.get("data");

		List competitors = (List) data.get("Competitors");

		for (int i = 0; i < competitors.size(); i++) {
			if (!judgeChips(_sid, 3, logFile)) {
				Thread.sleep(1000 * 60 * ShuaTa.sleepTime);
				return null;
			}
			Object item = competitors.get(i);
			Map competitor = (Map) item;
			if (!filterChip(competitor)) {
				log("NO Chip.");
				continue;
			}
			if (!filterRank(competitor)) {
				log("Rank too high.");
				continue;
			}
			if (!filterWin(competitor)) {
				log("Win too much.");
				continue;
			}
			return competitor.get("Uid").toString();
		}
		return null;
	}
	
	private static void log(String result) throws IOException{
		print(logFile, result);
	}

	@SuppressWarnings("rawtypes")
	public static boolean filterChip(Map competitor) {
		return ((Boolean) competitor.get("Chip")).booleanValue();
	}

	@SuppressWarnings("rawtypes")
	public static boolean filterRank(Map competitor) {
		return ((Double) competitor.get("Rank")).intValue() > competeRank;
	}

	@SuppressWarnings("rawtypes")
	public static boolean filterWin(Map competitor) {
		int win = (Double.valueOf(competitor.get("Win").toString())).intValue();
		int lose = (Double.valueOf(competitor.get("Lose").toString()))
				.intValue();
		if (win == 0 && lose >= 2)
			return true;
		if (win * 1.0 / (win + lose) * 100 < winRate)
			return true;
		return false;
	}

	public static String readGzip(HttpMethod method) throws IOException {
		String acceptEncoding = "";
		if (method.getResponseHeader("Content-Encoding") != null)
			acceptEncoding = method.getResponseHeader("Content-Encoding")
					.getValue();
		StringBuffer sb = new StringBuffer();
		if (acceptEncoding.toLowerCase().indexOf("gzip") > -1) {

			InputStream is = method.getResponseBodyAsStream();
			try {
				GZIPInputStream gzin = new GZIPInputStream(is);
				InputStreamReader isr = new InputStreamReader(gzin);
				java.io.BufferedReader br = new java.io.BufferedReader(isr);
				String tempbf;
				while ((tempbf = br.readLine()) != null) {
					sb.append(tempbf);
					sb.append("\r\n");
				}
				isr.close();
				gzin.close();
			} finally {
				is.close();
			}
		} else {
			InputStreamReader isr = new InputStreamReader(
					method.getResponseBodyAsStream());
			try {
				java.io.BufferedReader br = new java.io.BufferedReader(isr);
				String tempbf;
				while ((tempbf = br.readLine()) != null) {
					sb.append(tempbf);
					sb.append("\r\n");
				}
			} finally {
				isr.close();
			}
		}
		return sb.toString();
	}
}
